package net.stogi.unicore.beyond.api.model;

import java.util.ArrayList;
import java.util.List;

import net.stogi.unicore.beyond.api.exception.OutputDefinitionAlreadyExistsException;

public class OutputGroup extends Entity {

	private static final long serialVersionUID = 3707394725866340823L;

	private int index;

	private String name;

	private List<OutputDefinition> outputDefinitions;
	
	private TaskDefinition taskDefinition;

	public OutputGroup() {
		outputDefinitions = new ArrayList<OutputDefinition>();
	}

	public OutputGroup(String name) {
		this();
		this.name = name;
	}

	public OutputDefinition addOutputDefinition(OutputDefinition outputDefinition) {
		outputDefinition.setIndex(outputDefinitions.size());
		outputDefinitions.add(outputDefinition);
		outputDefinition.setOutputGroup(this);
		return outputDefinition;
	}

	public OutputDefinition addOutputDefinition(String name, OutputType outputType) throws OutputDefinitionAlreadyExistsException {
		assert name != null;
		assert outputType != null;
		if (containsOutputDefinitionWithName(name)) {
			throw new OutputDefinitionAlreadyExistsException(name);
		}
		OutputDefinition outputDefinition = new OutputDefinition(name, outputType);
		return addOutputDefinition(outputDefinition);
	}

	public boolean containsOutputDefinitionWithName(String name) {
		assert name != null;
		int count = 0;
		for (OutputDefinition outputDefinition : outputDefinitions) {
			if (name.equals(outputDefinition.getName())) {
				count++;
			}
		}
		if (count == 0) {
			return false;
		}
		return true;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (!(obj instanceof InputGroup)) {
			return false;
		}
		OutputGroup other = (OutputGroup) obj;
		// Check name.
		if (name == null) {
			if (other.name != null) {
				return false;
			}
		}
		else if (!name.equals(other.name)) {
			return false;
		}
		// Check index.
		if (index != other.index) {
			return false;
		}
		return true;
	}

	public int getIndex() {
		return index;
	}
	
	public String getName() {
		return name;
	}

	public List<OutputDefinition> getOutputDefinitions() {
		return outputDefinitions;
	}
	
	public TaskDefinition getTaskDefinition() {
		return taskDefinition;
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		result = prime * result + index;
		return result;
	}

	public boolean moveOutputDefinition(OutputDefinition outputDefinition, int offset) {
		assert outputDefinition != null;
		final int index = outputDefinition.getIndex();
		final int newIndex = index + offset;
		if (newIndex < 0 || newIndex >= outputDefinitions.size()) {
			// TODO: Maybe exception ?
			return false;
		}
		outputDefinitions.remove(index);
		outputDefinitions.add(newIndex, outputDefinition);
		final int start, end;
		if (newIndex < index) {
			start = newIndex;
			end = index;
		}
		else {
			start = index;
			end = newIndex;
		}
		for (int i = start; i <= end; i++) {
			outputDefinitions.get(i).setIndex(i);
		}
		return true;
	}

	public boolean removeOutputDefinition(OutputDefinition outputDefinition) {
		assert outputDefinition != null;
		boolean removed = false;
		final int removedIndex = outputDefinition.getIndex();
		if (outputDefinitions.remove(outputDefinition)) {
			removed = true;
			for (int index = removedIndex; index < outputDefinitions.size(); index++) {
				outputDefinitions.get(index).setIndex(index);
			}
		}
		return removed;
	}

	public OutputDefinition selectOutputDefinitionByName(String name) {
		assert name != null;
		OutputDefinition selectedOutputDefinition = null;
		for (OutputDefinition outputDefinition : outputDefinitions) {
			if (name.equals(outputDefinition.getName())) {
				selectedOutputDefinition = outputDefinition;
				break;
			}
		}
		return selectedOutputDefinition;
	}
	
	public OutputDefinition selectOutputDefinitionWithId(Long id) {
		assert id != null;
		OutputDefinition selectedOutputDefinition = null;
		for (OutputDefinition outputDefinition : outputDefinitions) {
			if (id.equals(outputDefinition.getId())) {
				selectedOutputDefinition = outputDefinition;
				break;
			}
		}
		return selectedOutputDefinition;
	}
	
	public void setIndex(int index) {
		this.index = index;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void setOutputDefinitions(List<OutputDefinition> outputDefinitions) {
		this.outputDefinitions = outputDefinitions;
	}

	public void setTaskDefinition(TaskDefinition taskDefinition) {
		this.taskDefinition = taskDefinition;
	}
}
